package com.jemframework.domain;

import com.jemframework.Context;
import com.jemframework.JagUtils;
import com.jemframework.domain.delegator.DelegatorFactory;
import com.jemframework.domain.delegator.PrePersistDelegator;
import com.jemframework.domain.delegator.PreUpdateDelegator;
import com.jemframework.domain.exception.EntityAttributeException;
import com.jemframework.domain.identifier.Identifier;
import com.jemframework.domain.validator.AttributeValidatorFactory;

public abstract class AbstractEntity implements Entity {

  private Identifier id;

  public AbstractEntity(Identifier id) {

    if (id == null) {
      throw new IllegalArgumentException("Null is not allowed.");
    }

    this.id = id;
    setDefaultValues();
  }

  protected void setDefaultValues() {
    // nothing to do.
  }

  protected DelegatorFactory getDelegatorFactory() {
    return Context.getInstance().getDelegatorFactory();
  }

  public void prePersist() {
    DelegatorFactory theFactory = getDelegatorFactory();
    PrePersistDelegator theDelegator = theFactory.getPrePersistDelegator(getEntityType());
    if (theDelegator != null) {
      theDelegator.prePersist(this);
    }
  }

  public void preUpdate() {
    DelegatorFactory theFactory = getDelegatorFactory();
    PreUpdateDelegator theDelegator = theFactory.getPreUpdateDelegator(getEntityType());
    if (theDelegator != null) {
      theDelegator.preUpdate(this);
    }
  }

  public void updateDependentEntitiesBeforeInsert() {
    // nothing to do by default.
  }

  public Identifier getId() {
    return id;
  }

  public void setId(Identifier anIdentifier) {
    id = anIdentifier;
  }

  public int getEntityType() {
    return getId().getEntityType();
  }

  public boolean equals(Object value) {

    if (value == null) {
      return false;
    }

    if (getClass() != value.getClass()) {
      return false;
    }

    Entity other = (Entity) value;
    return JagUtils.areEqual(getId(), other.getId());
  }

  public final int hashCode() {
    if (getId() != null) {
      return getId().hashCode();
    }

    // PK is not set
    // -> use the default implementation.
    return super.hashCode();
  }

  public final String toString() {
    return getId().toString();
  }

  protected AttributeValidatorFactory getAttributeValidatorFactory() {
    return Context.getInstance().getAttributeValidatorFactory();
  }

  @SuppressWarnings("unchecked")
  protected void validateAttribute(String aValidatorName, String anAttributeName, Object anAttributeValue, String aMessageId, Object... params)
      throws EntityAttributeException {

    AttributeValidator theValidator = getAttributeValidatorFactory().getAttributeValidator(aValidatorName, params);

    if (!theValidator.isValid(anAttributeValue)) {
      throw new EntityAttributeException(this, anAttributeName, anAttributeValue, aMessageId);
    }
  }

  public void updateFrom(Entity anEntity) {
    // does nothing by default.
  }
}
